package com.jt808.decode;

import com.alibaba.fastjson.JSON;
import com.jt808.decode.model.*;
import com.jt808.decode.utils.*;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.ByteBufUtil;
import io.netty.buffer.Unpooled;
import io.netty.util.ReferenceCountUtil;
import org.apache.commons.lang3.StringUtils;

import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;

/**
 * data decoding
 * @date 2023-03-02
 */
public class DataParser {

    /**
     * Parsing data
     * @param rowData raw data
     * @return JSON string
     */
    public static String receiveData(String rowData) throws Exception {
        if(StringUtils.isBlank(rowData)){
            return null;
        }
        //Convert Hex string to ByteBuf
        ByteBuf byteBuf = Unpooled.wrappedBuffer(ByteBufUtil.decodeHexDump(rowData));
        Object obj= Jt808PacketUtil.decodeJt808Packet(byteBuf);
        String resultJson="";
        if(obj==null){
            ReferenceCountUtil.release(byteBuf);
            return null;
        }else{
            Jt808Message jt808Msg= Jt808ProtocolDecoder.decode((ByteBuf)obj);
            switch (jt808Msg.getMsgId()){
                case 0x0001:
                    CommonReplyParam commonReplyParam= Message0001Parser.parse(jt808Msg,jt808Msg.getMsgBody());
                    resultJson=JSON.toJSONString(commonReplyParam);
                    break;
                case 0x0002:
                    Heartbeat heartbeat= Message0002Parser.parse(jt808Msg);
                    heartbeat.setReplyMsg(Jt808PacketUtil.reply8001(jt808Msg));
                    resultJson=JSON.toJSONString(heartbeat);
                    break;
                case 0x0100:
                    TerminalRegisterInfo registerInfo=Message0100Parser.parse(jt808Msg,jt808Msg.getMsgBody());
                    registerInfo.setReplyMsg(Jt808PacketUtil.reply8100(jt808Msg,registerInfo.getAuthCode()));
                    resultJson=JSON.toJSONString(registerInfo);
                    break;
                case 0x0102:
                    TerminalAuthInfo authInfo=Message0102Parser.parse(jt808Msg,jt808Msg.getMsgBody());
                    authInfo.setReplyMsg(Jt808PacketUtil.reply8001(jt808Msg));
                    resultJson=JSON.toJSONString(authInfo);
                    break;
                case 0x0104:
                    DeviceParam deviceParam=Message0104Parser.parse(jt808Msg,jt808Msg.getMsgBody());
                    resultJson=JSON.toJSONString(deviceParam);
                    break;
                case 0x0200:
                    Location location= Message0200Parser.parse(jt808Msg,jt808Msg.getMsgBody());
                    location.setReplyMsg(Jt808PacketUtil.reply8001(jt808Msg));
                    resultJson=JSON.toJSONString(location);
                    break;
                case 0x0600:
                    SummaryData summaryData= Message0600Parser.parse(jt808Msg,jt808Msg.getMsgBody());
                    summaryData.setReplyMsg(Jt808PacketUtil.reply8001(jt808Msg));
                    resultJson=JSON.toJSONString(summaryData);
                    break;
                case 0x0900:
                    PassThroughData throughData=Message0900Parser.parser(jt808Msg,jt808Msg.getMsgBody());
                    if(throughData.getMsgType()==0x53||throughData.getMsgType()==0x54){
                        throughData.setReplyMsg(Jt808PacketUtil.reply8001(jt808Msg));
                    }
                    resultJson=JSON.toJSONString(throughData);
                    break;
                default:
                    break;
            }
        }
        return resultJson;
    }

    /**
     * Split data
     * @param rowData
     * @return
     */
    public static List<String> splitData(String rowData){
        if(StringUtils.isBlank(rowData)){
            return null;
        }
        List<String> dataArr=new ArrayList<>();
        //将Hex字符串转成ByteBuf
        ByteBuf byteBuf = Unpooled.wrappedBuffer(ByteBufUtil.decodeHexDump(rowData));
        Object obj= Jt808PacketUtil.decodeJt808Packet(byteBuf);
        if(obj==null){
            ReferenceCountUtil.release(byteBuf);
            return null;
        }else{
            ByteBuf msgBuf= (ByteBuf) obj;
            dataArr.add(String.format("%s-->%s",NumberUtil.hexStr(msgBuf.readUnsignedByte(),2),"Start Flag"));
            int msgId=msgBuf.readUnsignedShort();
            dataArr.add(String.format("%s-->%s",NumberUtil.hexStr(msgId,4),"Message ID"));
            //message body properties
            short msgBodyAttr = msgBuf.readShort();
            //Version ID (version ID 0 refers to the version in 2011 and 1 refers to the version in 2019)
            int versionFlag = (msgBodyAttr & 0b01000000_00000000)>0?1:0;
            //is multi packet?
            boolean multiPacket = (msgBodyAttr & 0b00100000_00000000) > 0;
            dataArr.add(String.format("%s-->%s",NumberUtil.hexStr(msgBodyAttr,4),"Properties of Message Body"));
            //Terminal phone number array,JT808-2019 is 10 bytes
            byte[] phoneNumberArr;
            if (versionFlag == 1) {
                dataArr.add(String.format("%s-->%s",NumberUtil.hexStr(msgBuf.readUnsignedByte(),2),"Protocol Version"));
                phoneNumberArr = new byte[10];
            } else {
                phoneNumberArr = new byte[6];
            }
            msgBuf.readBytes(phoneNumberArr);
            dataArr.add(String.format("%s-->%s",ByteBufUtil.hexDump(phoneNumberArr),"Device Number"));
            //Message serial number
            int msgFlowId = msgBuf.readUnsignedShort();
            dataArr.add(String.format("%s-->%s",NumberUtil.hexStr(msgFlowId,4),"Message serial number"));
            //multi packet?
            if (multiPacket) {
                dataArr.add(String.format("%s-->%s",NumberUtil.hexStr(msgBuf.readUnsignedShort(),4),"Packet Total Count"));
                dataArr.add(String.format("%s-->%s",NumberUtil.hexStr(msgBuf.readUnsignedShort(),4),"Packet Order"));
            }
            //message body length
            int msgBodyLen = msgBodyAttr & 0b00000011_11111111;
            if(msgBodyLen>msgBuf.readableBytes()-2){
                byte[] msgBodyArr=new byte[msgBuf.readableBytes()-2];
                msgBuf.readBytes(msgBodyArr);
                dataArr.add(String.format("%s-->%s",ByteBufUtil.hexDump(msgBodyArr),"Insufficient message body length!"));
            }else{
                ByteBuf msgBodyBuf =msgBuf.readSlice(msgBuf.readableBytes()-2);
                switch (msgId){
                    case 0x0001:
                        dataArr.add(String.format("%s-->%s",NumberUtil.hexStr(msgBodyBuf.readShort(),4),"Response serial number"));
                        dataArr.add(String.format("%s-->%s",NumberUtil.hexStr(msgBodyBuf.readShort(),4),"Response message ID"));
                        dataArr.add(String.format("%s-->%s",NumberUtil.hexStr(msgBodyBuf.readShort(),2),"Results (0: success; 1: failure; 2: message error; 3: not supported)"));
                        break;
                    case 0x0002:
                        if(msgBodyBuf.readableBytes()>0){
                            byte[] msgBodyArr=new byte[msgBodyBuf.readableBytes()];
                            msgBodyBuf.readBytes(msgBodyArr);
                            dataArr.add(String.format("%s-->%s",ByteBufUtil.hexDump(msgBodyArr),"Message Body"));
                        }
                        break;
                    case 0x0100:
                        if(versionFlag == 1){
                            SplitUtil.splitTerminalRegisterInfo(msgBodyBuf,dataArr);
                        }else{
                            SplitUtil.splitTerminalRegisterInfo2019(msgBodyBuf,dataArr);
                        }
                        break;
                    case 0x0102:
                        SplitUtil.splitAuthInfo(msgBodyBuf,dataArr,versionFlag);
                        break;
                    case 0x0104:
                        SplitUtil.splitTerminalParameterResponse(msgBodyBuf,dataArr);
                        break;
                    case 0x0200:
                        SplitUtil.splitLocationInfo(msgBodyBuf,dataArr);
                        break;
                    case 0x0900:
                        dataArr.add(String.format("%s-->%s",NumberUtil.hexStr(msgBodyBuf.readUnsignedByte(),2),"Transparent message type"));
                        if(msgBodyBuf.readableBytes()>0){
                            byte [] msgContentArr=new byte[msgBodyBuf.readableBytes()];
                            msgBodyBuf.readBytes(msgContentArr);
                            dataArr.add(String.format("%s-->%s",ByteBufUtil.hexDump(msgContentArr),"Transparent message content"));
                        }
                        break;
                    default:
                        byte[] msgBodyArr=new byte[msgBodyBuf.readableBytes()];
                        msgBodyBuf.readBytes(msgBodyArr);
                        dataArr.add(String.format("%s-->%s",ByteBufUtil.hexDump(msgBodyArr),"Message Body"));
                        break;
                }
            }
            dataArr.add(String.format("%s-->%s",NumberUtil.hexStr(msgBuf.readUnsignedByte(),2),"Check Code"));
            dataArr.add(String.format("%s-->%s",NumberUtil.hexStr(msgBuf.readUnsignedByte(),2),"End Flag"));
        }
        return dataArr;
    }

    /**
     * Command Encoding
     * @param paramsJson
     * @return
     */
    public static String encodeCommand(String paramsJson){
        try {
            CommandParams commandParams = JSON.parseObject(paramsJson, CommandParams.class);
            byte[] bodyArr = new byte[0];
            if(commandParams.getMsgId()==0x8103){
                bodyArr= BuildMessageBody.build8103MessageBody(commandParams.getParams());
            }else if(commandParams.getMsgId()==0x8104){
                bodyArr = new byte[0];
            }else if(commandParams.getMsgId()==0x8105){
                bodyArr= BuildMessageBody.build8105MessageBody(commandParams.getParams());
            }else if(commandParams.getMsgId()==0x8300){
                bodyArr= BuildMessageBody.build8300MessageBody(commandParams.getParams());
            }else if(commandParams.getMsgId()==0x8900){
                bodyArr= BuildMessageBody.build8900MessageBody(commandParams.getParams());
            }else if(commandParams.getMsgId()==0x8A00){
                bodyArr= BuildMessageBody.build8A00MessageBody(commandParams.getStrKeyParams());
            }
            byte [] fullMessageArr=CommonUtil.packetFullCommandMessage(commandParams,bodyArr);
            if(fullMessageArr!=null){
                return ByteBufUtil.hexDump(fullMessageArr);
            }else{
                return "";
            }
        }catch (Exception e){
            return "";
        }
    }
}
